package com.hc.interceptor;


import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Slf4j
@Component
@Aspect
public class LogInterceptor {
    private String logStr = "";

    //用来做环绕通知的方法可以第一个参数定义为org.aspectj.lang.ProceedingJoinPoint类型
    @Around("execution(* com.hc.controller.*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest)
                requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //获取请求用户的IP地址
        String ipAddr = getRemoteHost(request);
        //获取用户请求的具体路径
        String url = request.getRequestURL().toString();
        log.info("************  请求IP：{},请求URL：{}", ipAddr, url);

        //获取类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();

        //相当于前置通知
        logStr ="************  "+ className + "类的" + methodName + "方法开始执行  ************";
        log.info(logStr);

        //获取目标方法的参数信息
        Object[] obj = joinPoint.getArgs();
        log.info("************  请求的参数为：" + Arrays.toString(obj));
        //下面注释掉的代码没有可以省略掉
//        if (obj.length > 0) {
//            Enumeration<String> enumeration = request.getParameterNames();
//            Map<String, String> parameterMap = new HashMap();
//            while (enumeration.hasMoreElements()) {
//                String parameter = enumeration.nextElement();
//                parameterMap.put(parameter, request.getParameter(parameter));
//            }
//            ObjectMapper om = new ObjectMapper();
//            String str = om.writeValueAsString(parameterMap);
//            log.info("************  请求的参数为：" + str);
//        }
        Object result = null;
        try {
            result = joinPoint.proceed();
            //相当于后置通知
            logStr = "************  "+className + "." + methodName + "()方法正常执行结束...";
            log.info(logStr);
        } catch (Throwable e) {
            //相当于异常抛出后通知
            StackTraceElement stackTraceElement = e.getStackTrace()[e.getStackTrace().length - 1];
            Object[] args = joinPoint.getArgs();

            log.error("----------------------------------------------------------------------------------");
            log.error("********* 执行{}类的{}()方法的{}行", className, methodName, stackTraceElement.getLineNumber());
            log.error("********* 异常信息为：{}  ", e.fillInStackTrace().toString());
            log.error("********* 参数信息为：{}  ", args);
            throw e;
        } finally {
            //相当于最终通知
            logStr = "************  "+ className + "类的" + methodName + "方法执行结束，结果是：{}  ************";
            log.info(logStr, result);
        }
        return result;
    }

    /**
     * 获取目标主机的ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

}